#ifndef __PROCESS_POOL_HPP__
#define __PROCESS_POOL_HPP__
#include "Signal.hpp"
#include <string>
#include <sys/types.h>
#include <sys/wait.h>
#define DEFAULTNUM 5

class Channel
{
public:
    Channel(int wfd, pid_t subid)
        : _wfd(wfd), _subid(subid)
    {
        /* 设置name */
        _name = "Channel-写入端口" + std::to_string(_wfd) + "控制的子进程ID:" + std::to_string(_subid);
    }

    void Close()
    {
        close(_wfd);
    }

    void Wait()
    {
        waitpid(_subid, nullptr, 0);
    }

    void Send(int code)
    {
        write(_wfd, &code, sizeof(code));
    }

    /* 主要函数 */

    /* 获取Channel信息 */
    int GetWfd() { return _wfd; }
    pid_t GetSubid() { return _subid; }
    std::string GetName() { return _name; }

    ~Channel()
    {}

private:
    int _wfd; /* 写端端口 */
    pid_t _subid;
    std::string _name;
};

class ChannelManage
{
public:
    ChannelManage()
        : _next(0)
    {}

    void InsertToCm(int wfd, pid_t subid)
    {
        _c.emplace_back(wfd, subid);
    }

    Channel &SelectChannel()
    {
        /* 轮询筛选 */
        auto &c = _c[_next];
        _next++;
        _next %= _c.size();
        return c;
    }

    /* 方案三: 关闭所有的写入信道 */
    void CloseAllWrite()
    {
        for (auto &c : _c)
        {
            c.Close();
            std::cout << "关闭写端" << c.GetName() << std::endl;
        }
    }

    /* 方案一: 分别处理写入端口和等待子进程 */
    void CloseWrite()
    {
        for (auto &c : _c)
        {
            c.Close();
            std::cout << "关闭写端" << c.GetName() << std::endl;   
        }
    }

    void CloseWait()
    {
        for (auto &c : _c)
        {
            c.Wait();
            std::cout << "回收进程" << c.GetName() << std::endl;
        }
    }

    /* 方案三 */
    void CloseWriteAndChild()
    {
        for (auto &c : _c)
        {
            c.Close();
            std::cout << "关闭写端" << c.GetName() << std::endl;
            c.Wait();
            std::cout << "回收进程" << c.GetName() << std::endl;
        }
    }


    /* 解决方法二 倒序关闭 */
    void R_CloseWriteAndChild()
    {
        for(int i = _c.size() - 1; i >= 0; --i)
        {
            _c[i].Close();
            std::cout << "关闭写端:" << _c[i].GetWfd() << std::endl;
            _c[i].Wait();
            std::cout << "回收进程:" << _c[i].GetSubid() << std::endl;
            std::cout << std::endl;
        }
    }

    void PrintName()
    {
        for (auto &c : _c)
            std::cout << c.GetName() << std::endl;
    }

    ~ChannelManage()
    {}

private:
    std::vector<Channel> _c;
    int _next; /* 用于轮询 */
};

class ProcessPool
{
public:
    ProcessPool()
        :_process_num(DEFAULTNUM)
    {
        _sm.InsertToSl(PrintLog);
        _sm.InsertToSl(DownLoad);
        _sm.InsertToSl(UpLoad);
    }

    void Work(int rfd)
    {
        while(true)
        {
            int code = 0;
            ssize_t n = read(rfd, &code, sizeof(code));
            if(n > 0)
            {
                if(n != sizeof(code))
                    continue;
                std::cout << "子进程:[PID->" << getpid() << "收到一个任务]" << std::endl;
                _sm.Execute(code); /* 执行任务 */
            }
            else if(n == 0) // read->end
            {
                std::cout << "子进程退出" << std::endl;
                break;
            }
            else
            {
                std::cout << "读取错误" << std::endl;
                break;
            }
        }
    }

    bool Start()
    {
        for (int i = 0; i < _process_num; ++i)
        {

            /* 1. 申请匿名通道 */
            int pipefd[2] = {0};
            int n = pipe(pipefd); /* pipefd[0]->读端 pipefd[1]->写端 */
            if (n < 0)
                return false;

            /* 2. 创建子程序 */
            pid_t subid = fork();
            if (subid < 0)
                return false;
            else if (subid == 0)
            {
                // child
                /* 方案三 */
                _cm.CloseAllWrite();
                /* 关闭写端 */
                close(pipefd[1]);
                /* 执行 */
                Work(pipefd[0]);
                /* 关闭读端 */
                close(pipefd[0]);
                exit(0);
            }
            else
            {
                // father
                /* 关闭读端 */
                close(pipefd[0]);
                _cm.InsertToCm(pipefd[1], subid);
            }
        }
        return true;
    }

    void Run()
    {
        /* 获取一个任务 */
        int taskcode = _sm.SelectCode();
        /* 选择一个信道 */
        auto& c = _cm.SelectChannel();
        std::cout << "选择了一个信道" << c.GetName() << std::endl;

        c.Send(taskcode);
        std::cout << "发送了一个信号码" << taskcode << std::endl;

    }

    void Debug()
    {
        _cm.PrintName();
    }

    void Stop()
    {
        /* 方案一 */
        /* 先关端口，再回收子进程 */
        // _cm.CloseWrite();
        // _cm.CloseWait();

        /* 方案二: 倒着关闭进程 */
        // _cm.R_CloseWriteAndChild();

        /* 方案三: 随意关闭*/


    }

    ~ProcessPool()
    {
    }

private:
    SignalManage _sm;
    ChannelManage _cm;
    int _process_num; /* 用于表示创建子进程的数量 */
};

#endif